package cn.sciento.starter.social.wechat.enterprise.connection;

import com.google.common.base.Charsets;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import cn.sciento.starter.social.core.common.connect.SocialTemplate;
import cn.sciento.starter.social.core.provider.Provider;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2Parameters;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

public class WechatEnterpriseTemplate extends SocialTemplate {
  private String clientId;
  
  private String agentId;
  
  private String clientSecret;
  
  private String accessTokenUrl;
  
  private String authorizeUrl;
  
  public WechatEnterpriseTemplate(Provider provider) {
    super(provider);
    setUseParametersForClientAuthentication(true);
    this.clientId = provider.getAppId();
    this.agentId = provider.getSubAppId();
    this.clientSecret = provider.getAppKey();
    this.authorizeUrl = provider.getAuthorizeUrl() + "?appid=" + this.clientId + "&agentid=" + this.agentId;
    this.accessTokenUrl = provider.getAccessTokenUrl() + "?corpid=" + this.clientId + "&corpsecret=" + this.clientSecret;
  }
  
  public String buildAuthenticateUrl(OAuth2Parameters parameters) {
    StringBuilder authUrl = new StringBuilder(this.authorizeUrl);
    for (Iterator<Map.Entry<String, List<String>>> additionalParams = parameters.entrySet().iterator(); additionalParams.hasNext(); ) {
      Map.Entry<String, List<String>> param = additionalParams.next();
      String name = formEncode(param.getKey());
      for (Iterator<String> values = ((List<String>)param.getValue()).iterator(); values.hasNext(); ) {
        authUrl.append('&').append(name);
        String value = values.next();
        if (StringUtils.hasLength(value)) {
          authUrl.append('=').append(formEncode(value));
        }
      } 
    } 
    return authUrl.toString();
  }
  
  public AccessGrant exchangeForAccess(String authorizationCode, String redirectUri, MultiValueMap<String, String> additionalParameters) {
    Map<String, Object> result = (Map<String, Object>)getRestTemplate().getForObject(this.accessTokenUrl, Map.class);
    if (result == null) {
      throw new RestClientException("access token endpoint returned empty result");
    }
    int errCode = ((Integer)result.get("errcode"));
    String errMsg = (String)result.get("errmsg");
    if (errCode != 0) {
      throw new RestClientException(errMsg);
    }
    String accessToken = (new StringBuilder()).append(result.get("access_token")).append("#").append(authorizationCode).toString();
    Long expireIn = Long.valueOf(String.valueOf(result.get("expires_in")));
    return createAccessGrant(accessToken, null, null, expireIn, null);
  }
  
  protected RestTemplate createRestTemplate() {
    RestTemplate restTemplate = super.createRestTemplate();
    restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charsets.UTF_8));
    return restTemplate;
  }
  
  private String formEncode(String data) {
    try {
      return URLEncoder.encode(data, "UTF-8");
    } catch (UnsupportedEncodingException ex) {
      throw new IllegalStateException(ex);
    } 
  }
}
